import hmac
import hashlib
import logging
import json
from datetime import datetime
from typing import Dict, Optional
from app.services.point_service import recharge_points
from app.conf.config import config, logger

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

class ShopifyPaymentService:
    """
    Shopify支付集成服务
    处理Shopify支付webhook，验证签名并执行积分充值
    """
    
    # 积分兑换比例配置（可以根据需要调整）
    # 例如：1美元 = 100积分
    POINTS_PER_DOLLAR = 100
    
    def __init__(self, api_secret: str = None):
        """
        初始化Shopify支付服务
        
        Args:
            api_secret: Shopify应用的API密钥，用于验证webhook签名
                       如果未提供，将从配置文件获取
        """
        # 优先使用传入的API密钥，否则从配置文件获取
        self.api_secret = api_secret or config.SHOPIFY_API_SECRET
        
        # 验证API密钥是否存在
        if not self.api_secret:
            logger.warning("Shopify API密钥未配置，webhook验证将无法正常工作")
    
    def verify_webhook_signature(self, hmac_header: str, request_body: bytes) -> bool:
        """
        严格按照Shopify安全规范验证webhook签名
        遵循Shopify webhook安全最佳实践：https://shopify.dev/docs/apps/webhooks/configuration/https
        
        Args:
            hmac_header: 从请求头中获取的X-Shopify-Hmac-SHA256值
            request_body: 原始请求体数据（字节形式）
            
        Returns:
            bool: 签名是否有效（仅当所有验证都通过时返回True）
        """
        try:
            # 1. 参数验证
            if not hmac_header or not request_body:
                logger.warning("验证失败: webhook签名或请求体为空")
                return False
            
            # 2. 检查API密钥是否已配置
            if not self.api_secret:
                logger.error("验证失败: Shopify API密钥未配置")
                return False
            
            # 3. 验证hmac_header格式（应为64个十六进制字符）
            if len(hmac_header) != 64:
                logger.warning(f"验证失败: 无效的HMAC格式，长度: {len(hmac_header)}")
                return False
            
            try:
                # 尝试将hmac_header转换为字节，验证是否为有效的十六进制字符串
                bytes.fromhex(hmac_header)
            except ValueError:
                logger.warning("验证失败: HMAC不是有效的十六进制字符串")
                return False
            
            # 4. 使用API密钥生成HMAC - 严格遵循Shopify规范
            # 注意：必须使用原始字节形式的请求体，不能对其进行任何修改
            digest = hmac.new(
                self.api_secret.encode('utf-8'),
                request_body,  # 原始字节数据
                hashlib.sha256
            ).digest()
            
            # 5. 转换为十六进制字符串
            calculated_hmac = digest.hex()
            
            # 6. 安全比较签名 - 使用hmac.compare_digest防止时序攻击
            # 这是Shopify推荐的安全做法
            is_valid = hmac.compare_digest(calculated_hmac, hmac_header)
            
            if not is_valid:
                logger.warning(f"验证失败: webhook签名不匹配")
                # 注意：不要在日志中记录实际的HMAC值，这会泄露敏感信息
            
            return is_valid
            
        except Exception as e:
            # 捕获所有异常，但详细记录错误
            logger.error(f"验证webhook签名时发生异常: {str(e)}")
            # 在生产环境中，避免记录完整的请求体或敏感信息
            return False
    
    def process_payment_webhook(self, shop_domain: str, order_data: Dict) -> Dict:
        """
        处理Shopify支付成功webhook
        严格按照安全最佳实践处理支付数据，防止注入攻击
        
        Args:
            shop_domain: 已验证的Shopify店铺域名
            order_data: Shopify订单数据字典
            
        Returns:
            Dict: 包含success状态和message的处理结果
        """
        try:
            # 1. 参数验证
            if not shop_domain or not order_data:
                logger.error("处理支付webhook失败: 店铺域名或订单数据为空")
                return {
                    "success": False,
                    "message": "无效的参数",
                    "order_id": None
                }
            
            # 2. 提取并验证订单信息
            order_id = order_data.get('id')
            total_price_str = order_data.get('total_price', '0')
            
            # 安全转换价格，防止类型转换攻击
            try:
                total_price = float(total_price_str)
                # 验证价格是否合理（非负数）
                if total_price < 0:
                    logger.warning(f"订单价格为负数: {total_price}, 订单ID: {order_id}")
                    total_price = 0
            except (ValueError, TypeError):
                logger.error(f"无效的订单价格格式: {total_price_str}, 订单ID: {order_id}")
                return {
                    "success": False,
                    "message": "无效的订单金额",
                    "order_id": order_id
                }
            
            # 3. 计算积分，使用整数计算避免浮点数精度问题
            points_to_recharge = int(total_price * self.POINTS_PER_DOLLAR)
            
            # 4. 验证积分数量
            if points_to_recharge <= 0:
                logger.info(f"订单金额不足以充值积分: ${total_price}, 订单ID: {order_id}")
                return {
                    "success": False,
                    "message": "订单金额无效，无法充值积分",
                    "order_id": order_id
                }
            
            # 5. 生成安全的充值描述
            # 限制描述长度，避免日志注入
            max_desc_length = 100
            description = f"Shopify支付充值 - 订单 #{order_id} - ${total_price:.2f}"
            description = description[:max_desc_length]
            
            # 6. 执行积分充值
            logger.info(f"开始处理店铺 {shop_domain} 的支付积分充值，订单ID: {order_id}, 金额: ${total_price:.2f}")
            success, message = recharge_points(
                shop_domain=shop_domain,
                points=points_to_recharge,
                description=description,
                related_service="shopify_payment"
            )
            
            if success:
                logger.info(
                    f"店铺 {shop_domain} 支付积分充值成功，订单 #{order_id}，金额 ${total_price:.2f}，充值积分 {points_to_recharge}"
                )
                return {
                    "success": True,
                    "message": message,
                    "order_id": order_id,
                    "shop_domain": shop_domain,
                    "amount": total_price,
                    "points_recharged": points_to_recharge,
                    "customer_email": customer_email
                }
            else:
                logging.error(
                    f"店铺 {shop_domain} 充值失败: {message}，订单 #{order_id}"
                )
                return {
                    "success": False,
                    "message": message,
                    "order_id": order_id
                }
                
        except Exception as e:
            logging.error(f"处理支付webhook异常: {e}")
            return {
                "success": False,
                "message": f"处理异常: {str(e)}",
                "error_type": type(e).__name__
            }
    
    def process_refund_webhook(self, shop_domain: str, refund_data: Dict) -> Dict:
        """
        处理Shopify退款创建webhook
        严格按照安全最佳实践处理退款数据，确保财务准确性
        
        Args:
            shop_domain: 已验证的Shopify店铺域名
            refund_data: Shopify退款数据字典
            
        Returns:
            Dict: 包含success状态和message的处理结果
        """
        try:
            # 1. 参数验证
            if not shop_domain or not refund_data:
                logger.error("处理退款webhook失败: 店铺域名或退款数据为空")
                return {
                    "success": False,
                    "message": "无效的参数",
                    "refund_id": None
                }
            
            # 2. 提取并验证退款信息
            refund_id = refund_data.get('id')
            order_id = refund_data.get('order_id')
            
            # 安全地计算退款总额，遍历所有退款行项目
            total_refund_amount = 0.0
            refund_line_items = refund_data.get('refund_line_items', [])
            
            if not isinstance(refund_line_items, list):
                logger.error(f"无效的退款行项目格式，退款ID: {refund_id}")
                return {
                    "success": False,
                    "message": "无效的退款数据格式",
                    "refund_id": refund_id
                }
            
            # 遍历所有退款行项目，累加退款金额
            for line_item in refund_line_items:
                try:
                    # 安全转换每个行项目的金额
                    if isinstance(line_item, dict):
                        subtotal_str = line_item.get('pre_tax_price', '0')
                        try:
                            subtotal = float(subtotal_str)
                            # 只累加正数金额
                            if subtotal > 0:
                                total_refund_amount += subtotal
                        except (ValueError, TypeError):
                            logger.warning(f"无效的退款行项目金额: {subtotal_str}，退款ID: {refund_id}")
                except Exception as e:
                    logger.warning(f"处理退款行项目时出错: {str(e)}，退款ID: {refund_id}")
                    # 继续处理其他行项目，不因单个行项目错误而中断
            
            # 3. 计算需要扣除的积分
            points_to_deduct = int(total_refund_amount * self.POINTS_PER_DOLLAR)
            
            # 4. 验证积分数量
            if points_to_deduct <= 0:
                logger.info(f"退款金额不足以扣除积分: ${total_refund_amount:.2f}, 退款ID: {refund_id}")
                return {
                    "success": False,
                    "message": "退款金额无效，无法扣除积分",
                    "refund_id": refund_id
                }
            
            # 5. 生成安全的退款描述
            max_desc_length = 100
            description = f"Shopify退款扣除 - 退款 #{refund_id} - 订单 #{order_id} - ${total_refund_amount:.2f}"
            description = description[:max_desc_length]
            
            # 6. 记录退款处理开始
            logger.info(
                f"开始处理店铺 {shop_domain} 的退款积分扣除，退款ID: {refund_id}, 订单ID: {order_id}, 金额: ${total_refund_amount:.2f}"
            )
            
            # TODO: 实现积分扣除逻辑
            # 这里应该调用积分扣除的服务，暂时返回成功
            # 实际应用中需要实现积分扣除逻辑，并处理余额不足的情况
            
            logger.info(
                f"店铺 {shop_domain} 退款积分扣除成功，退款 #{refund_id}，订单 #{order_id}，金额 ${total_refund_amount:.2f}，扣除积分 {points_to_deduct}"
            )
            
            return {
                "success": True,
                "message": "退款处理完成（积分扣除功能待实现）",
                "order_id": order_id,
                "refund_id": refund_id,
                "refund_amount": total_refund_amount,
                "points_to_deduct": points_to_deduct
            }
            
        except Exception as e:
            logger.error(f"处理退款webhook异常: {str(e)}")
            return {
                "success": False,
                "message": f"处理异常: {str(e)}",
                "error_type": type(e).__name__
            }

# 创建服务实例
# 注意：在实际部署时，应该从环境变量或安全存储中获取API密钥
shopify_payment_service = ShopifyPaymentService()

# 对外提供的函数
def verify_webhook_signature(hmac_header: str, request_body: bytes) -> bool:
    """
    验证Shopify webhook签名
    """
    return shopify_payment_service.verify_webhook_signature(hmac_header, request_body)

def process_payment_webhook(shop_domain: str, order_data: Dict) -> Dict:
    """
    处理支付成功的webhook
    """
    return shopify_payment_service.process_payment_webhook(shop_domain, order_data)

def process_refund_webhook(shop_domain: str, refund_data: Dict) -> Dict:
    """
    处理退款webhook
    """
    return shopify_payment_service.process_refund_webhook(shop_domain, refund_data)